﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Xts
{
    namespace Util
    {
        public class XThreadSafeQueue<T> : IDisposable
        {
            protected Queue<T> x_requestQueue;
            protected Object x_lockObj;
            protected short x_waitingReaders;

            public XThreadSafeQueue()
            {
                x_lockObj = new Object();
                x_requestQueue = new Queue<T>();
                x_waitingReaders = 0;
            }

            #region Dispose Resources
            public void Dispose()
            {
                Dispose(true);
                //take us off of the finalization queue
                GC.SuppressFinalize(this);
            }

            protected virtual void Dispose(bool disposing)
            {
                if (!this.disposed)
                {
                    if (disposing)
                    {
                        //dispose of managed resources......
                        x_requestQueue.Clear();
                    }
                    //dispose of unmanaged resources......
                    disposed = true;
                }
            }

            ~XThreadSafeQueue() { Dispose(false); }

            private bool disposed = false;
            #endregion

            public void Enqueue(T req)
            {
                lock (x_lockObj)
                {
                    x_requestQueue.Enqueue(req);
                    if (x_waitingReaders > 0)
                        Monitor.Pulse(x_lockObj);
                }
            }

            public T Dequeue()
            {
                lock (x_lockObj)
                {
                    while (x_requestQueue.Count == 0)
                    {
                        try
                        {
                            ++x_waitingReaders;
                            Monitor.Wait(x_lockObj);
                            --x_waitingReaders;
                        }
                        catch (Exception)
                        {
                            --x_waitingReaders;
                        }
                    }
                    return x_requestQueue.Dequeue();
                }
            }

            public void Clear()
            {
                lock (x_lockObj)
                {
                    x_requestQueue.Clear();
                }
            }
        }
    }
}

